home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-desktop-9.10-i386-PL.iso / casper / filesystem.squashfs / usr / share / pyshared / fstab.py < prev    next >
Text File  |  2009-08-21  |  6KB  |  204 lines

  1. # fstab.py - read, manipulate, and write /etc/fstab files
  2. # Copyright (C) 2008  Canonical, Ltd.
  3. #
  4. # This program is free software: you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation, version 3 of the License.
  7. #
  8. # This program is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11. # GNU General Public License for more details.
  12. #
  13. # You should have received a copy of the GNU General Public License
  14. # along with this program.  If not, see <http://www.gnu.org/licenses/>.
  15.  
  16.  
  17. import os
  18. import re
  19. import tempfile
  20.  
  21.  
  22. class Line(object):
  23.  
  24.     """A line in an /etc/fstab line.
  25.  
  26.     Lines may or may not have a filesystem specification in them. The
  27.     has_filesystem method tells the user whether they do or not; if they
  28.     do, the attributes device, directory, fstype, options, dump, and
  29.     fsck contain the values of the corresponding fields, as instances of
  30.     the sub-classes of the LinePart class. For non-filesystem lines,
  31.     the attributes have the None value.
  32.     
  33.     Lines may or may not be syntactically correct. If they are not,
  34.     they are treated as as non-filesystem lines.
  35.     
  36.     """
  37.  
  38.     # Lines split this way to shut up coverage.py.
  39.     attrs = ("ws1", "device", "ws2", "directory", "ws3", "fstype")
  40.     attrs += ("ws4", "options", "ws5", "dump", "ws6", "fsck", "ws7")
  41.  
  42.     def __init__(self, raw):
  43.         self.dict = {}
  44.         self.raw = raw
  45.  
  46.     def __getattr__(self, name):
  47.         if name in self.dict:
  48.             return self.dict[name]
  49.         else:
  50.             raise AttributeError(name)
  51.  
  52.     def __setattr__(self, name, value):
  53.         forbidden = ("dict", "dump", "fsck", "options")
  54.         if name not in forbidden and name in self.dict:
  55.             if self.dict[name] is None:
  56.                 raise Exception("Cannot set attribute %s when line dies not "
  57.                                 "contain filesystem specification" % name)
  58.             self.dict[name] = value
  59.         else:
  60.             object.__setattr__(self, name, value)
  61.  
  62.     def get_dump(self):
  63.         return int(self.dict["dump"])
  64.     
  65.     def set_dump(self, value):
  66.         self.dict["dump"] = str(value)
  67.  
  68.     dump = property(get_dump, set_dump)
  69.     
  70.     def get_fsck(self):
  71.         return int(self.dict["fsck"])
  72.  
  73.     def set_fsck(self, value):
  74.         self.dict["fsck"] = str(value)
  75.             
  76.     fsck = property(get_fsck, set_fsck)
  77.  
  78.     def get_options(self):
  79.         return self.dict["options"].split(",")
  80.             
  81.     def set_options(self, list):
  82.         self.dict["options"] = ",".join(list)
  83.         
  84.     options = property(get_options, set_options)
  85.             
  86.     def set_raw(self, raw):
  87.         match = False
  88.         
  89.         if raw.strip() != "" and not raw.strip().startswith("#"):
  90.             pat = r"^(?P<ws1>\s*)"
  91.             pat += r"(?P<device>\S*)"
  92.             pat += r"(?P<ws2>\s+)"
  93.             pat += r"(?P<directory>\S+)"
  94.             pat += r"(?P<ws3>\s+)"
  95.             pat += r"(?P<fstype>\S+)"
  96.             pat += r"(?P<ws4>\s+)"
  97.             pat += r"(?P<options>\S+)"
  98.             pat += r"(?P<ws5>\s+)"
  99.             pat += r"(?P<dump>\d+)"
  100.             pat += r"(?P<ws6>\s+)"
  101.             pat += r"(?P<fsck>\d+)"
  102.             pat += r"(?P<ws7>\s*)$"
  103.  
  104.             match = re.match(pat, raw)
  105.             if match:
  106.                 self.dict.update((attr, match.group(attr)) for attr in self.attrs)
  107.  
  108.         if not match:
  109.             self.dict.update((attr, None) for attr in self.attrs)
  110.  
  111.         self.dict["raw"] = raw
  112.  
  113.     def get_raw(self):
  114.         if self.has_filesystem():
  115.             return "".join(self.dict[attr] for attr in self.attrs)
  116.         else:
  117.             return self.dict["raw"]
  118.         
  119.     raw = property(get_raw, set_raw)
  120.  
  121.     def has_filesystem(self):
  122.         """Does this line have a filesystem specification?"""
  123.         return self.device is not None
  124.  
  125.  
  126. class Fstab(object):
  127.  
  128.     """An /etc/fstab file."""
  129.  
  130.     def __init__(self):
  131.         self.lines = []
  132.     
  133.     def open_file(self, filespec, mode):
  134.         if type(filespec) in (str, unicode):
  135.             return file(filespec, mode)
  136.         else:
  137.             return filespec
  138.  
  139.     def close_file(self, f, filespec):
  140.         if type(filespec) in (str, unicode):
  141.             f.close()
  142.  
  143.     def get_perms(self, filename):
  144.         return os.stat(filename).st_mode # pragma: no cover
  145.  
  146.     def chmod_file(self, filename, mode):
  147.         os.chmod(filename, mode) # pragma: no cover
  148.  
  149.     def link_file(self, oldname, newname):
  150.         if os.path.exists(newname):
  151.             os.remove(newname)
  152.         os.link(oldname, newname)
  153.  
  154.     def rename_file(self, oldname, newname):
  155.         os.rename(oldname, newname) # pragma: no cover
  156.     
  157.     def read(self, filespec):
  158.         """Read in a new file.
  159.         
  160.         If filespec is a string, it is used as a filename. Otherwise
  161.         it is used as an open file.
  162.         
  163.         The existing content is replaced.
  164.         
  165.         """
  166.         
  167.         f = self.open_file(filespec, "r")
  168.         lines = []
  169.         for line in f:
  170.             lines.append(Line(line))
  171.         self.lines = lines
  172.         self.close_file(filespec, f)
  173.  
  174.     def write(self, filespec):
  175.         """Write out a new file.
  176.         
  177.         If filespec is a string, it is used as a filename. Otherwise
  178.         it is used as an open file.
  179.         
  180.         """
  181.         
  182.         if type(filespec) in (str, unicode):
  183.             # We create the temporary file in the directory (/etc) that the
  184.             # file exists in. This is so that we can do an atomic rename
  185.             # later, and that only works inside one filesystem. Some systems
  186.             # have /tmp and /etc on different filesystems, for good reasons,
  187.             # and we need to support that.
  188.             dirname = os.path.dirname(filespec)
  189.             prefix = os.path.basename(filespec) + "."
  190.             fd, tempname = tempfile.mkstemp(dir=dirname, prefix=prefix)
  191.             os.close(fd)
  192.         else:
  193.             tempname = filespec
  194.     
  195.         f = self.open_file(tempname, "w")
  196.         for line in self.lines:
  197.             f.write(line.raw)
  198.         self.close_file(filespec, f)
  199.  
  200.         if type(filespec) in (str, unicode):
  201.             self.chmod_file(tempname, self.get_perms(filespec))
  202.             self.link_file(filespec, filespec + ".bak")
  203.             self.rename_file(tempname, filespec)
  204.